/**
 * 一些未位操作相关的工具
 */

#ifndef _AHAMOLETT_CLANG_DATASTRUCT_BITTOOL_H_
#define _AHAMOLETT_CLANG_DATASTRUCT_BITTOOL_H_
#ifdef __cplusplus
extern "C" {
#endif

#include <cds/cds_types.h>

/**
 * @brief 判断一个数是否是2的非负整数次幂。
 * 
 * @param num   进行判断的数
 * 
 * @retval true num是2的非负整数次幂。
 * @retval false num不是2的非负整数次幂。
 */
#define is_power_of_two(num)    ((num) > 0 && ((num) & ((num) - 1)) == 0)

/**
 * @brief 返回2^(order)
 */
#define get_ordered_size(order) (1UL << (order))

/**
 * @brief 获得按order对其需要的mask
 */
#define get_ordered_mask(order) (get_ordered_size(order) - 1)

/**
 * @brief 将 num 按照 2^(order) 大小向下对齐。
 * 
 * 要求num和order均是正整数。最终返回第一个小于等于num的2^(order)的非负整数倍数。
 * 
 * @param num 进行对齐的数。
 * @param order 向下对齐的order
 * 
 * @return typeof(num) num按照2^(order)大小向下对齐。
 */
#define get_order_aligned_down(num, order)  \
    ((num) & (~get_ordered_mask(order)))

/**
 * @brief 将 num 按照 2^(order) 大小向上对齐。
 * 
 * 要求num和order均是正整数。最终返回第一个大于等于num的2^(order)的非负整数倍数。
 * 
 * @param num 进行对齐的数。
 * @param order 向上对齐的order
 * 
 * @return typeof(num) num按照2^(order)大小向上对齐。
 */
#define get_order_aligned(num, order)    \
    get_order_aligned_down(((num) + get_ordered_mask(order)), order)

/**
 * @brief 将 num 按照 size 大小向下对齐。
 * 
 * 要求num和size均是正整数。最终返回第一个小于等于num的size的非负整数倍数。
 * 
 * @param num 进行对齐的数。
 * @param size 向下对齐的大小。
 * 
 * @return typeof(num) num按size向下对齐后的结果。
 */
#define get_size_aligned_down(num, size)    (((num) / (size)) * (size))

/**
 * @brief 将 num 按照 size 大小向上对齐。
 * 
 * 要求num和size均是正整数。最终返回第一个大于等于num的size的非负整数倍数。
 * 
 * @param num 进行对齐的数。
 * @param size 向上对齐的大小。
 * 
 * @return typeof(num) num按size向上对齐后的结果。
 */
#define get_size_aligned(num, size) \
    get_size_aligned_down(((num) + (size) - 1), size)

/**
 * @brief 测试是否flag中所有bits指定的位都被置位。
 * 
 * @param flag 进行位测试的数。
 * @param bits 需要测试的所有位。其中需要测试位被置一，其余的被置零。
 * 
 * @retval true flag中所有指定的位都被置位。
 * @retval false flag中有部分或全部被指定的位没有被置位。
 */
#define check_flag_bits(flag, bits) \
    ((__atomic_load_n(&(flag), __ATOMIC_ACQUIRE) & (bits)) == (bits))

/**
 * @brief 测试是否flag中存在bits指定的位被置位。
 * 
 * @param flag 进行位测试的数。
 * @param bits 需要测试的所有位。其中需要测试位被置一，其余的被置零。
 * 
 * @retval true flag存在部分或所有指定的位被置位。
 * @retval false flag没有指定的位被置位。
 */
#define check_flag_bits_any(flag, bits) \
    (!!(__atomic_load_n(&(flag), __ATOMIC_ACQUIRE) & (bits)))

/**
 * @brief 清除flag中所有bits指定的位。
 * 
 * @param flag 进行位操作的变量。
 * @param bits 需要清除的所有位。其中需要被清除的位被置一，其余的被置零。
 */
#define clear_flag_bits(flag, bits) do {    \
    __atomic_fetch_and(&(flag), ~(bits), __ATOMIC_SEQ_CST); \
} while (0)

/**
 * @brief 置位flag中所有bits指定的位。
 * 
 * @param flag 进行位操作的变量。
 * @param bits 需要置位的所有位。其中需要被置位的位被置一，其余的被置零。
 */
#define set_flag_bits(flag, bits)   do {    \
    __atomic_fetch_or(&(flag), bits, __ATOMIC_SEQ_CST); \
} while (0)


#ifdef __cplusplus
}
#endif
#endif  // #ifndef _AHAMOLETT_CLANG_DATASTRUCT_BITTOOL_H_
